﻿using System;
using System.Collections.Generic;
using System.Linq;
using DataStore;
using DataStore.Domain;
using DataStore.Repositories;
using System.ComponentModel;
using System.Windows.Input;
using Infrastructure.CurrentData;
using Microsoft.Practices.Composite.Events;

namespace Infrastructure.ViewModels
{
    /// <summary>
    /// ViewModel for CatalogItem
    /// </summary>
    public class CatalogItemViewModel: DataModelSingle<CatalogItem>, IDataErrorInfo
    {
        public CatalogItemViewModel()
        {
            Item = new CatalogItem();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CatalogItemViewModel"/> class.
        /// </summary>
        /// <param name="catalogItem">The catalog item.</param>
        public CatalogItemViewModel(CatalogItem catalogItem) : base(catalogItem)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CatalogItemViewModel"/> class.
        /// </summary>
        /// <param name="eventAggregator">The event aggregator.</param>
        /// <param name="catalogItem">The catalog item.</param>
        public CatalogItemViewModel(IEventAggregator eventAggregator, CatalogItem catalogItem) : base(eventAggregator, catalogItem)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        void Initialize()
        {
            State = ModelState.Active;
        }

        /// <summary>
        /// Gets the CatalogItem entity.
        /// </summary>
        /// <value>The CatalogItem entity.</value>
        //public CatalogItem CatalogItem { get { return Item; } }

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id.</value>
        public virtual Guid Id
        {
            get
            {
                return Item.Id;
            }
            set
            {
                if (Item.Id != value)
                {
                    Item.Id = value;
                    OnPropertyChanged("Id");
                }
            }
        }

        /// <summary>
        /// Gets or sets the document type.
        /// </summary>
        /// <value>The type.</value>
        public virtual DocumentType Type
        {
            get
            {
                return Item.Type;
            }
            set
            {
                if (Item.Type != value)
                {
                    Item.Type = value;
                    OnPropertyChanged("Type");
                }
            }
        }
        /// <summary>
        /// The name(s) of the author(s).
        /// </summary>
        /// <value>The author.</value>
        public virtual IList<AuthorViewModel> Authors
        {
            get
            {
                List<AuthorViewModel> authors = new List<AuthorViewModel>();
                foreach (var author in Item.Authors)
                {
                    authors.Add(new AuthorViewModel(EventAggregator, author));
                }
                return authors;
            }
            set
            {
                List<Author> authors = new List<Author>();
                foreach (var author in value)
                {
                    authors.Add(author.Author);
                }
                Item.Authors = authors;
                OnPropertyChanged("Authors");
            }
        }
        /// <summary>
        /// Name(s) of editor(s). If there is also an author field, then the editor field gives 
        /// the editor of the book or collection in which the reference appears.
        /// </summary>
        /// <value>The editor.</value>
        public virtual ICollection<Editor> Editors
        {
            get
            {
                return Item.Editors;
            }
            set
            {
                Item.Editors = value;
                OnPropertyChanged("Editors");
            }
        }
        /// <summary>
        /// A chapter (or section or whatever) number.
        /// </summary>
        /// <value>The chapter.</value>
        public virtual string Chapter
        {
            get
            {
                return Item.Chapter;
            }
            set
            {
                if (Item.Chapter != value)
                {
                    Item.Chapter = value;
                    OnPropertyChanged("Chapter");
                }
            }
        }
        /// <summary>
        /// The edition of a book - for example, "Second". 
        /// This should be an ordinal, and should have the first letter capitalized, as shown here; 
        /// the standard styles convert to lower case when necessary.
        /// </summary>
        /// <value>The edition.</value>
        public virtual string Edition
        {
            get
            {
                return Item.Edition;
            }
            set
            {
                if (Item.Edition != value)
                {
                    Item.Edition = value;
                    OnPropertyChanged("Edition");
                }
            }
        }
        /// <summary>
        /// How something strange has been published. The first word should be capitalized.
        /// </summary>
        /// <value>The how published.</value>
        public virtual string HowPublished
        {
            get
            {
                return Item.HowPublished;
            }
            set
            {
                if (Item.HowPublished != value)
                {
                    Item.HowPublished = value;
                    OnPropertyChanged("HowPublished");
                }
            }
        }
        /// <summary>
        /// The sponsoring institution of a technical report.
        /// </summary>
        /// <value>The institution.</value>
        public virtual ICollection<Company> Sponsors
        {
            get
            {
                return Item.Sponsors;
            }
            set
            {
                Item.Sponsors = value;
                OnPropertyChanged("Sponsors");
            }
        }
        /// <summary>
        /// Gets or sets the date written.
        /// </summary>
        /// <value>The date written.</value>
        public virtual DateTime? DateWritten
        {
            get
            {
                return Item.DateWritten;
            }
            set
            {
                if (Item.DateWritten != value)
                {
                    Item.DateWritten = value;
                    OnPropertyChanged("DateWritten");
                }
            }
        }
        /// <summary>
        /// Gets or sets the date published.
        /// </summary>
        /// <value>The date published.</value>
        public virtual DateTime? DatePublished
        {
            get
            {
                return Item.DatePublished;
            }
            set
            {
                if (Item.DatePublished != value)
                {
                    Item.DatePublished = value;
                    OnPropertyChanged("DatePublished");
                }
            }
        }
        /// <summary>
        /// Gets or sets the comments.
        /// </summary>
        /// <value>The comments.</value>
        public virtual string Comment
        {
            get
            {
                return Item.Comment;
            }
            set
            {
                if (Item.Comment != value)
                {
                    Item.Comment = value;
                    OnPropertyChanged("Comment");
                }
            }
        }
        /// <summary>
        /// One or more page numbers or range of numbers.
        /// </summary>
        /// <value>The pages.</value>
        public virtual ICollection<Range> Pages
        {
            get
            {
                return Item.Pages;
            }
            set
            {
                Item.Pages = value;
                OnPropertyChanged("Pages");
            }
        }
        /// <summary>
        /// The publisher's name.
        /// </summary>
        /// <value>The publisher.</value>
        public virtual Company Publisher
        {
            get
            {
                return Item.Publisher;
            }
            set
            {
                if (Item.Publisher != value)
                {
                    Item.Publisher = value;
                    OnPropertyChanged("Publisher");
                }
            }
        }
        /// <summary>
        /// The name of a series or set of books.
        /// </summary>
        /// <value>The series.</value>
        public virtual string Series
        {
            get
            {
                return Item.Series;
            }
            set
            {
                if (Item.Series != value)
                {
                    Item.Series = value;
                    OnPropertyChanged("Series");
                }
            }
        }
        /// <summary>
        /// The work's title.
        /// </summary>
        /// <value>The title.</value>
        public virtual string Title
        {
            get
            {
                return Item.Title;
            }
            set
            {
                if (Item.Title != value)
                {
                    Item.Title = value;
                    OnPropertyChanged("Title");
                }
            }
        }
        /// <summary>
        /// The type of a technical report - for example, "Research Note".
        /// </summary>
        /// <value>The type of the report.</value>
        public virtual string ReportType
        { 
            get
            {
                return Item.ReportType;
            }
            set
            {
                if (Item.ReportType != value)
                {
                    Item.ReportType = value;
                    OnPropertyChanged("ReportType");
                }
            }
        }
        /// <summary>
        /// The volume of a journal or multi-volume book.
        /// </summary>
        /// <value>The volume.</value>
        public virtual string Volume 
        { 
            get
            {
                return Item.Volume;
            }
            set
            {
                if (Item.Volume != value)
                {
                    Item.Volume = value;
                    OnPropertyChanged("Volume");
                }
            }
        }
        /// <summary>
        /// Gets or sets the links of the document.
        /// </summary>
        /// <value>The link.</value>
        public virtual IList<LinkViewModel> Links
        {
            get
            {
                List<LinkViewModel> links = new List<LinkViewModel>();
                foreach (var link in Item.Links)
                {
                    links.Add(new LinkViewModel(EventAggregator, link));
                }
                return links;
            }
            set
            {
                List<Link> links = new List<Link>();
                foreach (var link in value)
                {
                    links.Add(link.Link);
                }
                Item.Links = links;
                OnPropertyChanged("Links");
            }
        }
        /// <summary>
        /// Gets or sets the country of publication.
        /// </summary>
        /// <value>The country.</value>
        public virtual Country Country
        {
            get
            {
                return Item.Country;
            }
            set
            {
                if (Item.Country != value)
                {
                    Item.Country = value;
                    OnPropertyChanged("Country");
                }
            }
        }
        /// <summary>
        /// Gets or sets the language of the document.
        /// </summary>
        /// <value>The language.</value>
        public virtual Language Language
        {
            get
            {
                return Item.Language;
            }
            set
            {
                if (Item.Language != value)
                {
                    Item.Language = value;
                    OnPropertyChanged("Language");
                }
            }
        }
        /// <summary>
        /// Gets or sets the width of the document.
        /// </summary>
        /// <value>The width.</value>
        public virtual float? Width
        {
            get
            {
                return Item.Width;
            }
            set
            {
                if (Item.Width != value)
                {
                    Item.Width = value;
                    OnPropertyChanged("Width");
                }
            }
        }
        /// <summary>
        /// Gets or sets the height of the document.
        /// </summary>
        /// <value>The height.</value>
        public virtual float? Height
        {
            get
            {
                return Item.Height;
            }
            set
            {
                if ( Item.Height != value)
                {
                    Item.Height = value;
                    OnPropertyChanged("Height");
                }
            }
        }
        /// <summary>
        /// Gets or sets the cover.
        /// </summary>
        /// <value>The cover.</value>
        public virtual IList<CoverViewModel> Cover
        {
            get
            {
                List<CoverViewModel> covers = new List<CoverViewModel>();
                foreach (var cover in Item.Cover)
                {
                    covers.Add(new CoverViewModel(EventAggregator, cover));
                }
                return covers;
            }
            set
            {
                List<Cover> covers = new List<Cover>();
                foreach (var cover in value)
                {
                    covers.Add(cover.Cover);
                }
                Item.Cover = covers;
                OnPropertyChanged("Cover");
            }
        }

        /// <summary>
        /// Gets the front covers.
        /// </summary>
        /// <value>The front covers.</value>
        public virtual IEnumerable<CoverViewModel> FrontCovers
        {
            get
            {
                VerifyCalledOnUIThread();
                var covers = from c in Cover
                             where c.Type == CoverType.Front
                             select c;
                return covers;
            }
        }

        // TODO rewrite to use cover repository
        public virtual CoverViewModel FrontCoverDefault
        {
            get
            {
                return FrontCovers.FirstOrDefault();
            }
        }

        /// <summary>
        /// Gets the back covers.
        /// </summary>
        /// <value>The back covers.</value>
        public virtual IEnumerable<CoverViewModel> BackCovers
        {
            get
            {
                VerifyCalledOnUIThread();
                var covers = from c in Cover
                             where c.Type == CoverType.Back
                             select c;
                return covers;
            }
        }

        // TODO rewrite to use cover repository
        public virtual CoverViewModel BackCoverDefault
        {
            get
            {
                return BackCovers.FirstOrDefault();
            }
        }

        /// <summary>
        /// Gets or sets the number of pages.
        /// </summary>
        /// <value>The number of pages.</value>
        public virtual int? NumberOfPages
        {
            get
            {
                return Item.NumberOfPages;
            }
            set
            {
                if (Item.NumberOfPages != value)
                {
                    Item.NumberOfPages = value;
                    OnPropertyChanged("NumberOfPages");
                }
            }
        }
        /// <summary>
        /// Gets or sets the publishing format of the document.
        /// </summary>
        /// <value>The format.</value>
        public virtual PublishingFormat Format
        {
            get
            {
                return Item.Format;
            }
            set
            {
                if (Item.Format != value)
                {
                    Item.Format = value;
                    OnPropertyChanged("Format");
                }
            }
        }
        /// <summary>
        /// Gets or sets the citations found in the document.
        /// </summary>
        /// <value>The citations.</value>
        public virtual ICollection<CatalogItem> Citations
        {
            get
            {
                return Item.Citations;
            }
            set
            {
                if(Item.Citations != value)
                {
                    Item.Citations = value;
                    OnPropertyChanged("Citations");
                }
            }
        }
        /// <summary>
        /// Gets or sets the keywords.
        /// </summary>
        /// <value>The keywords.</value>
        public virtual ICollection<Keyword> Keywords 
        { 
            get
            {
                return Item.Keywords;   
            }
            set
            {
                if (Item.Keywords != value)
                {
                    Item.Keywords = value;
                    OnPropertyChanged("Keywords");
                }
            }
        }
        /// <summary>
        /// Gets or sets the categories.
        /// </summary>
        /// <value>The categories.</value>
        public virtual ICollection<Category> Categories
        {
            get
            {
                return Item.Categories;
            }
            set
            {
                if (Item.Categories != value)
                {
                    Item.Categories = value;
                    OnPropertyChanged("Categories");
                }
            }
        }
        /// <summary>
        /// Gets or sets the contents.
        /// </summary>
        /// <value>The contents.</value>
        public virtual string Contents
        {
            get
            {
                return Item.Contents;
            }
            set
            {
                if (Item.Contents != value)
                {
                    Item.Contents = value;
                    OnPropertyChanged("Contents");
                }
            }
        }
        /// <summary>
        /// Gets or sets the owner of the document.
        /// </summary>
        /// <value>The owner.</value>
        public virtual Person Owner
        {
            get
            {
                return Item.Owner;
            }
            set
            {
                if (Item.Owner != value)
                {
                    Item.Owner = value;
                    OnPropertyChanged("Owner");
                }
            }
        }
        /// <summary>
        /// Gets or sets the purchase date.
        /// </summary>
        /// <value>The purchase date.</value>
        public virtual DateTime? PurchaseDate
        {
            get
            {
                return Item.PurchaseDate;
            }
            set
            {
                if (Item.PurchaseDate != value)
                {
                    Item.PurchaseDate = value;
                    OnPropertyChanged("PurchaseDate");
                }
            }
        }
        /// <summary>
        /// Gets or sets the purchase store.
        /// </summary>
        /// <value>The purchase store.</value>
        public virtual Company PurchaseStore
        {
            get
            {
                return Item.PurchaseStore;
            }
            set
            {
                if (Item.PurchaseStore != value)
                {
                    Item.PurchaseStore = value;
                    OnPropertyChanged("PurchaseStore");
                }
            }
        }
        /// <summary>
        /// Gets or sets the purchase price.
        /// </summary>
        /// <value>The purchase price.</value>
        public virtual float? PurchasePrice
        {
            get
            {
                return Item.PurchasePrice;
            }
            set
            {
                if (Item.PurchasePrice != value)
                {
                    Item.PurchasePrice = value;
                    OnPropertyChanged("PurchasePrice");
                }
            }
        }
        /// <summary>
        /// Gets or sets the current price.
        /// </summary>
        /// <value>The current price.</value>
        public virtual float? CurrentPrice
        {
            get
            {
                return Item.CurrentPrice;
            }
            set
            {
                if (Item.CurrentPrice != value)
                {
                    Item.CurrentPrice = value;
                    OnPropertyChanged("CurrentPrice");
                }
            }
        }
        /// <summary>
        /// Gets or sets the condition.
        /// </summary>
        /// <value>The condition.</value>
        public virtual Condition Condition
        {
            get
            {
                return Item.Condition;
            }
            set
            {
                if (Item.Condition != value)
                {
                    Item.Condition = value;
                    OnPropertyChanged("Condition");
                }
            }
        }
        /// <summary>
        /// Gets or sets the rating.
        /// </summary>
        /// <value>The rating.</value>
        public virtual int? Rating
        {
            get
            {
                return Item.Rating;
            }
            set
            {
                if (Item.Rating != value)
                {
                    Item.Rating = value;
                    OnPropertyChanged("Rating");
                }
            }
        }
        /// <summary>
        /// Gets or sets the dedication.
        /// </summary>
        /// <value>The dedication.</value>
        public virtual string Dedication
        {
            get
            {
                return Item.Dedication; 
            }
            set
            {
                if (Item.Dedication != value)
                {
                    Item.Dedication = value;
                    OnPropertyChanged("Dedication");
                }
            }
        }
        /// <summary>
        /// Gets or sets the reading date.
        /// </summary>
        /// <value>The reading date.</value>
        public virtual DateTime? ReadingDate
        {
            get
            {
                return Item.ReadingDate;
            }
            set
            {
                if (Item.ReadingDate != value)
                {
                    Item.ReadingDate = value;
                    OnPropertyChanged("ReadingDate");
                }
            }
        }

        /// <summary>
        /// Gets or sets the borrower.
        /// </summary>
        /// <value>The borrower.</value>
        public virtual Person Borrower
        {
            get
            {
                return Item.Borrower;
            }
            set
            {
                if (Item.Borrower != value)
                {
                    Item.Borrower = value;
                    OnPropertyChanged("Borrower");
                }
            }
        }
        /// <summary>
        /// Gets or sets the borrow date.
        /// </summary>
        /// <value>The borrow date.</value>
        public virtual DateTime? BorrowDate
        {
            get
            {
                return Item.BorrowDate;
            }
            set
            {
                if (Item.BorrowDate != value)
                {
                    Item.BorrowDate = value;
                    OnPropertyChanged("BorrowDate");
                }
            }
        }

        /// <summary>
        /// Gets or sets the extras.
        /// </summary>
        /// <value>The extras.</value>
        public virtual ICollection<Extra> Extras
        {
            get
            {
                return Item.Extras;
            }
            set
            {
                Item.Extras = value;
                OnPropertyChanged("Extras");
            }
        }

        /// <summary>
        /// Gets or sets the Library of Congress classification.
        /// </summary>
        /// <value>The lo C classification.</value>
        public virtual string LoCClassification
        {
            get
            {
                return Item.LoCClassification;
            }
            set
            {
                if (Item.LoCClassification != value)
                {
                    Item.LoCClassification = value;
                    OnPropertyChanged("LoCClassification");
                }
            }
        }
        /// <summary>
        /// Gets or sets the Dewey classification.
        /// </summary>
        /// <value>The dewey classification.</value>
        public virtual string DeweyClassification
        {
            get
            {
                return Item.DeweyClassification;
            }
            set
            {
                if (Item.DeweyClassification != value)
                {
                    Item.DeweyClassification = value;
                    OnPropertyChanged("DeweyClassification");
                }
            }
        }

        /// <summary>
        /// Gets or sets the other classification.
        /// </summary>
        /// <value>The other classification.</value>
        public virtual Classification OtherClassification
        {
            get
            {
                return Item.OtherClassification;
            }
            set
            {
                if (Item.OtherClassification != value)
                {
                    Item.OtherClassification = value;
                    OnPropertyChanged("OtherClassification");
                }
            }
        }

        /// <summary>
        /// Gets or sets the copyright.
        /// </summary>
        /// <value>The copyright.</value>
        public virtual string Copyright
        {
            get
            {
                return Item.Copyright;
            }
            set
            {
                if (Item.Copyright != value)
                {
                    Item.Copyright = value;
                    OnPropertyChanged("Copyright");
                }
            }
        }
        /// <summary>
        /// Gets or sets the quantity.
        /// </summary>
        /// <value>The quantity.</value>
        public virtual int? Quantity
        {
            get
            {
                return Item.Quantity;
            }
            set
            {
                if (Item.Quantity != value)
                {
                    Item.Quantity = value;
                    OnPropertyChanged("Quantity");
                }
            }
        }
        /// <summary>
        /// Gets or sets the location of the document.
        /// </summary>
        /// <value>The location.</value>
        public virtual string Location
        {
            get
            {
                return Item.Location;
            }
            set
            {
                if (Item.Location != value)
                {
                    Item.Location = value;
                    OnPropertyChanged("Location");
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether thye entity is a new item.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if the entity is a new item; otherwise, <c>false</c>.
        /// </value>
        protected override bool IsNewItem
        {
            get
            {
                return Item.Id == Guid.Empty;
            }
        }

        /// <summary>
        /// Saves the entity.
        /// </summary>
        public override void Save()
        {
            IDatabase database = Current.Container.Resolve<IDatabase>();
            using (var unitOfWork = database.CreateUnitOfWork())
            {
                try
                {
                    IRepository<CatalogItem> repository = new CatalogItemRepository(unitOfWork);
                    unitOfWork.BeginTransaction();
                    repository.SaveOrUpdate(Item);
                    unitOfWork.CommitTransaction();
                    base.Save();
                }
                catch
                {
                    unitOfWork.RollbackTransaction();
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether the entity can be saved.
        /// </summary>
        /// <value><c>true</c> if the entity can be saved; otherwise, <c>false</c>.</value>
        protected override bool CanSave
        {
            get
            {
                return Item.IsValid;
            }
        }



        #region IDataErrorInfo Members

        /// <summary>
        /// Gets an error message indicating what is wrong with this object.
        /// </summary>
        /// <value></value>
        /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
        public virtual string Error
        {
            get { return (Item as IDataErrorInfo).Error; }
        }

        /// <summary>
        /// Gets the <see cref="System.String"/> with the specified column name.
        /// </summary>
        /// <value></value>
        public virtual string this[string columnName]
        {
            get 
            {
                string error = string.Empty;
                error = (Item as IDataErrorInfo)[columnName];

                CommandManager.InvalidateRequerySuggested();
                return error;
            }
            
        }

        #endregion

        /// <summary>
        /// Deletes the catalog item.
        /// </summary>
        protected override void Delete()
        {
            IDatabase database = Current.Container.Resolve<IDatabase>();
            using (var unitOfWork = database.CreateUnitOfWork())
            {
                try
                {
                    IRepository<CatalogItem> repository = new CatalogItemRepository(unitOfWork);
                    unitOfWork.BeginTransaction();
                    repository.Delete(Item);
                    unitOfWork.CommitTransaction();
                }
                catch (Exception)
                {
                    unitOfWork.RollbackTransaction();
                    throw;
                }
                
            }
            PublishDeletedItem(this);
        }
    }
}